﻿/* 
    Copyright (c) 2010 Microsoft Corporation.  All rights reserved.
    Use of this sample source code is subject to the terms of the Microsoft license 
    agreement under which you licensed this sample source code and is provided AS-IS.
    If you did not accept the terms of the license agreement, you are not authorized 
    to use this sample source code.  For the terms of the license, please see the 
    license agreement between you and Microsoft.
    
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace HidingObjects
{

    /// <summary>
    /// This sample draws a large number of multicolored rectangles and then animates to squares on top of them.
    /// The buttons allow you to hide the rectangles, either by setting their opacity to 0 or by setting their
    /// visibility to collapsed. You can also toggle the CachedMode property of the background rectangles on and off.
    /// By trying different combinations of these settings, you can see how the frame rate of the animation is affected.
    /// You can also see the difference in the amount of time it takes for the rectangles to reappear when different
    /// settings are used.
    /// </summary>
    public partial class MainPage : PhoneApplicationPage
    {
        private List<Rectangle> _rectList;
        private List<bool> _rectDirection;
        private List<Color> _rectColors;
        private Random _rand;
        private bool _isRedraw = false;
        private bool _isVisible = true;
        private bool _direction = true;
        private bool _isCached = true;
        private double _opacity = 1.0;
        private DateTime _lastTick;

        /// <summary>
        /// The constructor for the page.
        /// </summary>
        public MainPage()
        {
            InitializeComponent();

            // Enable the frame rate counter.
            Application.Current.Host.Settings.EnableFrameRateCounter = true;

            // Lists for the background rectangles.
            _rectList = new List<Rectangle>();
            _rectDirection = new List<bool>();
            _rectColors = new List<Color>() { Colors.Blue, Colors.Red, Colors.Green, Colors.Cyan, Colors.Magenta, Colors.Orange, Colors.Purple, Colors.Yellow, Colors.Brown, Colors.Gray };
            _rand = new Random();

            // Helper method to create the background rectangles.
            CreateRects();

            // Add a handler for the CompositionTarget.Rendering event. This is raised once per frame and is used
            // to animate the blue square.
            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
            _lastTick = DateTime.Now;
        }
        /// <summary>
        /// Helper method to create the background rectangles.
        /// </summary>
        public void CreateRects()
        {
            for (int i = 0; i < 150; i++)
            {
                Rectangle newRect = new Rectangle();
                newRect.Height = 800;
                newRect.Width = 60;


                // Create a linear gradient brush with five stops  
                LinearGradientBrush lgb = new LinearGradientBrush();
                lgb.StartPoint = new Point(0, 0);
                lgb.EndPoint = new Point(1, 1);

                // Create and add Gradient stop
                GradientStop blueGS = new GradientStop();
                blueGS.Color = Colors.Blue;
                blueGS.Offset = (i % 5) * 0.25;
                lgb.GradientStops.Add(blueGS);

                GradientStop orangeGS = new GradientStop();
                orangeGS.Color = Colors.Orange;
                orangeGS.Offset = ((i + 1) % 5) * 0.25;
                lgb.GradientStops.Add(orangeGS);

                GradientStop yellowGS = new GradientStop();
                yellowGS.Color = Colors.Yellow;
                yellowGS.Offset = ((i + 2) % 5) * 0.25;
                lgb.GradientStops.Add(yellowGS);

                GradientStop greenGS = new GradientStop();
                greenGS.Color = Colors.Green;
                greenGS.Offset = ((i + 3) % 5) * 0.25;
                lgb.GradientStops.Add(greenGS);

                GradientStop redGS = new GradientStop();
                redGS.Color = Colors.Red;
                redGS.Offset = ((i + 4) % 5) * 0.25;
                lgb.GradientStops.Add(redGS);

                newRect.Fill = lgb;

                // Choose a random horizontal location for the current rectangle.
                newRect.SetValue(Canvas.TopProperty, (double)0);
                newRect.SetValue(Canvas.LeftProperty, (double)_rand.Next(420));

                // Set the CacheMode for each rectangle to BitmapCache. This can be toggled with the Cache button.
                newRect.CacheMode = new BitmapCache();

                // Add the rectangle to the list.
                _rectList.Add(newRect);

                // Set the direction of the rectangle's animation to forward.
                _rectDirection.Add(true);

                // Add the rectangle to the LayoutRoot.
                this.LayoutRoot.Children.Add(newRect);
            }
        }

        /// <summary>
        /// The CompositionTarget.Rendering event is raised once per frame. It can be used to create frame based
        /// animation. In this example, a red square, defined in the XAML for this page as "perFrameRect" is animated
        /// back and forth across the screen by updating its position in this handler. This update occurs in the UI thread.
        /// The blue square in the sample is animated on the
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void CompositionTarget_Rendering(object sender, EventArgs e)
        {

            // Use the time elapsed between frames to scale the distance the square moves per frame.
            DateTime now = DateTime.Now;
            TimeSpan elapsed = now - _lastTick;
            _lastTick = now;
            double elapsedModifier = (elapsed.Milliseconds / 16.0);

            // Get the current location of the square.
            double x = (double)perFrameRect.GetValue(Canvas.LeftProperty);

            // Move the square. If the square moves outside of the screen width, reverse the direction.
            if (_direction == false)
            {
                x = x - 3 * elapsedModifier;
                if (x <= 0)
                {
                    _direction = true;
                }

                perFrameRect.SetValue(Canvas.LeftProperty, x);
            }
            else
            {
                x = x + 3 * elapsedModifier;
                if (x >= 480)
                {
                    _direction = false;
                }

                perFrameRect.SetValue(Canvas.LeftProperty, x);
            }


        }

        /// <summary>
        /// Button click handler for the opacity button. This toggles the opacity of the background rectangles between 0 and 1.
        /// Note that when caching is enabled and opacity is greater than 0, the animation does not run smoothly. When caching 
        /// is disabled, the animation is smooth regardless of opacity. Also, notice that when caching is enabled, the rectangles 
        /// reappear more quickly when you toggle the opacity than when you toggle the visibility.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void opacity0Btn_Click(object sender, RoutedEventArgs e)
        {
            // If _opacity is 0, set all of the rectangles to opacity = 1.
            if (_opacity == 0)
            {
                foreach (Rectangle rect in _rectList)
                {
                    rect.Opacity = 1.0;
                }
                _opacity = 1.0;

                // Update the opacity button.
                opacity0Btn.Content = "Opac 0%";
            }
            // If _opacity is 1, set all of the rectangles to opacity = 0.
            else
            {
                foreach (Rectangle rect in _rectList)
                {
                    rect.Opacity = 0.00;
                }
                _opacity = 0.00;

                // Update the opacity button.
                opacity0Btn.Content = "Opac 100%";
            }
        }

        /// <summary>
        /// Button click handler for the collapse button. This toggles the Visibility of the background rectangles between Visible and Collapsed.
        /// Note that when caching is enabled and Visibility is set to Visible, the animation does not run smoothly. When caching 
        /// is disabled, the animation is smooth regardless of visibility. Also, notice that when caching is enabled, the rectangles 
        /// reappear more slowly when you toggle the visibility than when you toggle the opacity.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void collapseBtn_Click(object sender, RoutedEventArgs e)
        {
            // If _isVisible is true, set the Visibility of all rectangles to Collapsed.
            if (_isVisible)
            {
                foreach (Rectangle rect in _rectList)
                {
                    rect.Visibility = Visibility.Collapsed;
                }
                _isVisible = false;

                // Update the collapse button.
                collapseBtn.Content = "Visible";
            }
            // If _isVisible is false, set the Visibility of all rectangles to Visible.
            else
            {
                foreach (Rectangle rect in _rectList)
                {
                    rect.Visibility = Visibility.Visible;
                }
                _isVisible = true;

                // Update the collapse button.
                collapseBtn.Content = "Collapse";
            }
        }
        /// <summary>
        /// Toggles the cache mode of the background rectangles. Note that when caching is disabled, the
        /// animation is smooth regardless of the visibility or opacity of the background rectangles.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cacheBtn_Click(object sender, RoutedEventArgs e)
        {
            // If _isCached is true, set the CacheMode of all rectangles to null.
            if (_isCached)
            {
                foreach (Rectangle rect in _rectList)
                {
                    rect.CacheMode = null;
                }
                _isCached = false;

                // Update cacheDisplay TextBlock
                cacheDisplay.Text = "Cache Off";
            }
            else
            // If _isCached is true, set the CacheMode of all rectangles to BitmapCache.
            {
                foreach (Rectangle rect in _rectList)
                {
                    rect.CacheMode = new BitmapCache();
                }
                _isCached = true;

                // Update cacheDisplay TextBlock
                cacheDisplay.Text = "Cache On";
            }
        }
    }
}
